﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TankController.Dominio
{
    public abstract class ControladorMalhaFechada : AbstractControlador
    {
        protected double ganho;
        protected IEntrada referencia;
        protected TipoPosicaoControlador tipoPosicao;
        protected ISinal sinalReferencia = new Sinal("Referência", TipoSinal.Referencia);
        protected ISinal sinalErro = new Sinal("Erro", TipoSinal.Erro);

        //protected double valorSaidaAnterior = 0;

        protected override void Controlar()
        {
            double valorReferencia = referencia.GetValorAmplitude(tempoAtual);
            double valorProcesso = planta.Ler() * planta.FatorConversao;
            double valorErro = (valorReferencia - valorProcesso);
            double valorSaida = 0;
            double valorSaidaCorrigido = 0;

            if (Global.TipoConfiguracao == TipoConfiguracao.ConfiguracaoA)
            {
                valorSaida = CalcularSaida(valorErro, valorProcesso) / planta.FatorConversao;

                valorSaidaCorrigido = ManterNivelSeguranca(valorProcesso, valorSaida);

                planta.Escrever(valorSaidaCorrigido);

                sinalProcessoSensor1.AdicionarPonto(tempoAtual, valorProcesso);
            }
            else
            {
                if (Global.TipoConfiguracao == TipoConfiguracao.ConfiguracaoB)
                {
                    double valorProcessoAuxiliar = planta.LerSensorSecundario() * planta.FatorConversao;

                    valorSaida = CalcularSaida(valorErro, valorProcesso) / planta.FatorConversao;

                    valorSaidaCorrigido = ManterNivelSeguranca(valorProcessoAuxiliar, ManterNivelSeguranca(valorProcesso, valorSaida));

                    planta.Escrever(valorSaidaCorrigido);

                    sinalProcessoSensor2.AdicionarPonto(tempoAtual, valorProcesso);
                    sinalProcessoSensor1.AdicionarPonto(tempoAtual, valorProcessoAuxiliar);
                }
                else if (Global.TipoConfiguracao == TipoConfiguracao.ConfiguracaoC)
                {
                    if (tipoPosicao == TipoPosicaoControlador.Controlador1)
                    {
                        //valorSaidaCorrigido = ManterNivelSeguranca(valorProcesso, valorSaida);

                        valorSaida = CalcularSaida(valorErro, valorProcesso);

                        valorSaidaCorrigido = valorSaida;

                        planta.Escrever(valorSaidaCorrigido);

                        sinalProcessoSensor1.AdicionarPonto(tempoAtual, valorProcesso);
                    }
                    else if (tipoPosicao == TipoPosicaoControlador.Controlador2)
                    {
                        valorSaida = CalcularSaida(valorErro, valorProcesso) / planta.FatorConversao;
                        
                        valorSaidaCorrigido = ManterNivelSeguranca(valorProcesso, valorSaida);

                        planta.Escrever(valorSaidaCorrigido);

                        sinalProcessoSensor1.AdicionarPonto(tempoAtual, valorProcesso);
                    }
                    else
                    {
                        throw new ApplicationException("Tipo de posição do controlador inválida.");
                    }
                }
            }

            //valorSaidaAnterior = valorSaidaCorrigido;

            referencia.GerarPontoSinal(tempoAtual, valorReferencia, sinalReferencia);
            sinalErro.AdicionarPonto(tempoAtual, valorErro);
            sinalSaida.AdicionarPonto(tempoAtual, valorSaidaCorrigido);
        }

        protected abstract double CalcularSaida(double valorErro, double valorProcesso);

        protected void ConfigurarSinais(TipoPosicaoControlador tipoPosicao)
        {
            if (Global.TipoConfiguracao == TipoConfiguracao.ConfiguracaoC)
            {
                if (tipoPosicao == TipoPosicaoControlador.Controlador1)
                {
                    sinalProcessoSensor1.Descricao = "Nível Tanque 2";
                    sinalReferencia.Descricao = "Referência Controlador 1";
                    sinalErro.Descricao = "Erro Controlador 1";
                    sinalSaida.Descricao = "Saída Controlador 1";

                    sinalProcessoSensor1.Tipo = TipoSinal.Resposta;
                }
                else if (tipoPosicao == TipoPosicaoControlador.Controlador2)
                {
                    sinalProcessoSensor1.Descricao = "Nível Tanque 1";
                    sinalReferencia.Descricao = "Referência Controlador 2";
                    sinalErro.Descricao = "Erro Controlador 2";
                    sinalSaida.Descricao = "Saída Controlador 2";

                    sinalProcessoSensor1.Tipo = TipoSinal.Nivel;
                }
                else
                {
                    throw new ApplicationException("Tipo de posição do controlador inválida.");
                }
            }
        }

        public override IList<ISinal> GetSinaisAltura()
        {
            IList<ISinal> sinalList = new List<ISinal>();

            sinalList.Add(sinalReferencia);
            sinalList.Add(sinalProcessoSensor1);

            if (Global.TipoConfiguracao != TipoConfiguracao.ConfiguracaoA && Global.TipoConfiguracao != TipoConfiguracao.ConfiguracaoC)
            {
                sinalList.Add(sinalProcessoSensor2);
            }

            return sinalList;
        }

        public override IList<ISinal> GetSinaisTensao()
        {
            IList<ISinal> sinalList = new List<ISinal>();

            sinalList.Add(sinalErro);
            sinalList.Add(sinalSaida);

            return sinalList;
        }

        public override double Ganho
        {
            get { return ganho; }
            set { ganho = value; }
        }
        public IEntrada Referencia
        {
            get { return referencia; }
            set { referencia = value; }
        }
        public ISinal SinalReferencia
        {
            get { return sinalReferencia; }
            set { sinalReferencia = value; }
        }
        public ISinal SinalErro
        {
            get { return sinalErro; }
            set { sinalErro = value; }
        }
    }
}
